package org.ysling.litemall.core.tenant.config;

import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.util.StringUtils;
import org.ysling.litemall.core.tenant.enums.IgnoreRequestNames;
import org.ysling.litemall.core.tenant.enums.IgnoreTableNames;
import org.ysling.litemall.core.tenant.enums.IgnoreTenant;
import org.ysling.litemall.core.utils.GlobalWebUtil;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;

/**
 * 多租户处理插件
 */
public class CustomTenantLineHandler implements TenantLineHandler {

    /**租户ID InheritableThreadLocal子线程共享值，且线程独立，可解决并发问题*/
    private static final ThreadLocal<Long> localTenantId = new ThreadLocal<>();
    /**租户请求头*/
    private static final String TENANT_ID_HEADER = "X-Litemall-TenantId";


    /**
     * 获取租户 ID 值表达式，只支持单个 ID 值
     * <p>
     *
     * @return 租户 ID 值表达式
     */
    @Override
    public Expression getTenantId() {
        return new LongValue(returnTenantId());
    }

    /**
     * 获取租户字段名
     * <p>
     * 默认字段名叫: tenant_id
     *
     * @return 租户字段名
     */
    @Override
    public String getTenantIdColumn() {
        return "tenant_id";
    }

    /**
     * 根据表名判断是否忽略拼接多租户条件
     * <p>
     * 默认都要进行解析并拼接多租户条件
     *
     * @param tableName 表名
     * @return 是否忽略, true:表示忽略，false:需要解析并拼接多租户条件
     */
    @Override
    public boolean ignoreTable(String tableName) {
        //未携带请求头拦截所有表
        if(Objects.equals(getByTenantId(), IgnoreTenant.FAIL.tenantId)){
            return false;
        }
        //租户ID为零则忽略所有表
        if(Objects.equals(getByTenantId(),IgnoreTenant.DEFAULT.tenantId)){
            return true;
        }
        return IgnoreTableNames.parseValue(tableName);
    }

    /**
     * 设置当前租户
     * @param tenantId 当前租户id
     * @return 当前租户id
     */
    public static Long setTenantId(Long tenantId){
        localTenantId.remove();
        localTenantId.set(tenantId);
        return tenantId;
    }

    /**
     * 获取当前租户
     * @return 当前租户id
     */
    public static Long getByTenantId(){
        return localTenantId.get();
    }


    /**
     * 从请求中获取到token，从请求头中解析出tenantId
     * @return
     */
    public static Long returnTenantId() {
        //获取当前请求如果没有请求则是内部调用返回默认值 0
        HttpServletRequest request = GlobalWebUtil.getRequest();
        if (Objects.isNull(request)){
            return setTenantId(IgnoreTenant.DEFAULT.tenantId);
        }

        //获取请求地址如果为白名单地址则返回默认值 0
        String requestURI = request.getRequestURI();
        if (IgnoreRequestNames.parseValue(requestURI)){
            return setTenantId(IgnoreTenant.DEFAULT.tenantId);
        }

        //获取请求头如果未携带请求头则返回 -1
        String tenantId = WebUtils.toHttp(request).getHeader(TENANT_ID_HEADER);
        if (!StringUtils.hasText(tenantId)){
            return setTenantId(IgnoreTenant.DEFAULT.tenantId);
        }

        //添加密钥对中的租户
        return setTenantId(Long.valueOf(tenantId));
    }

}
